﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using hello.csharp.common.Interfaces;
using MongoDB.Driver;
using NLog;

namespace hello.csharp.storage.Db
{
    /// <summary>
    /// 系统的数据库管理器
    /// </summary>
    public sealed class DbManager : IDbManager
    {
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();

        private const string POSTGRESQL_WRITE_CONN = "Server={\"localhost\"};Port={\"5432\"};User Id={\"postgres\"};Password={\"postgrespass\"};Database={\"testdb\"};";
        private const string POSTGRESQL_READ_CONN = "Server={\"localhost\"};Port={\"5432\"};User Id={\"postgres\"};Password={\"postgrespass\"};Database={\"testdb\"};";
        private const string SQLITE_WRITE_CONN = @"Data Source=z:\hello-csharp.sqlite;Version=3;";
        private const string SQLITE_READ_CONN = @"Data Source=z:\hello-csharp.sqlite;Version=3;";

        private IDbConnection _farReadConnection;
        private IDbConnection _farWriteConnection;

        public DbManager(INosqlDbManager nosqlDb, IDbInitialise dbInitialise)
        {
            NosqlDb = nosqlDb;
            dbInitialise.SetConnections(new Func<IDbConnection>[] {OpenReadConnection, OpenWriteConnection});
            dbInitialise.Run();
            ConnectionParamChanged += (s, e) =>
            {
                _logger.Info("Connection Param Changed.");
                _farReadConnection = null;
                _farWriteConnection = null;
            };
        }

        /// <summary>
        /// 当数据库连接参数发生变化时发生。一般在外界配置文件发生改变时变化。
        /// </summary>
        public event EventHandler<EventArgs> ConnectionParamChanged;

        /// <summary>
        /// 返回一个NoSQL数据库管理器
        /// </summary>
        public INosqlDbManager NosqlDb { get; }

        /// <summary>
        ///     打开“写”数据库连接，并返回该连接
        /// </summary>
        /// <returns>数据库连接</returns>
        public IDbConnection OpenWriteConnection()
        {
            if (_farWriteConnection != null
                && _farWriteConnection.State != ConnectionState.Broken
                && _farWriteConnection.State != ConnectionState.Closed) 
                return _farWriteConnection;

            if (_farWriteConnection != null && _farWriteConnection.State == ConnectionState.Broken)
                _farWriteConnection.Close();

            if (_farWriteConnection != null && _farWriteConnection.State == ConnectionState.Closed)
            {
                _farWriteConnection.Open();
                return _farWriteConnection;
            }

            if (_farWriteConnection == null)
            {
#if DEBUG
                _farWriteConnection = new SQLiteConnection(SQLITE_WRITE_CONN);
#else
                _farWriteConnection = new NpgsqlConnection(POSTGRESQL_WRITE_CONN);
#endif
                _farWriteConnection.Open();
            }

            return _farWriteConnection;
        }

        /// <summary>
        ///     关闭数据库连接
        /// </summary>
        public void CloseWriteConnection()
        {
            if (_farWriteConnection == null)
                return;
            _farWriteConnection.Close();
            _farWriteConnection.Dispose();
            _farWriteConnection = null;
        }

        /// <summary>
        ///     打开“写”数据库连接，并返回该连接
        /// </summary>
        /// <returns>数据库连接</returns>
        public IDbConnection OpenReadConnection()
        {
            if (_farReadConnection != null
                && _farReadConnection.State != ConnectionState.Broken
                && _farReadConnection.State != ConnectionState.Closed)
                return _farReadConnection;

            if (_farReadConnection != null && _farReadConnection.State == ConnectionState.Broken) _farReadConnection.Close();

            if (_farReadConnection != null && _farReadConnection.State == ConnectionState.Closed)
            {
                _farReadConnection.Open();
                return _farReadConnection;
            }

            if (_farReadConnection == null)
            {
#if DEBUG
                _farReadConnection = new SQLiteConnection(SQLITE_READ_CONN);
#else
                _farReadConnection = new NpgsqlConnection(POSTGRESQL_READ_CONN);
#endif
                _farReadConnection.Open();
            }

            return _farReadConnection;
        }

        /// <summary>
        ///     关闭数据库连接
        /// </summary>
        public void CloseReadConnection()
        {
            if (_farReadConnection == null)
                return;
            _farReadConnection.Close();
            _farReadConnection.Dispose();
            _farReadConnection = null;
        }

        private void OnConnectionParamChanged()
        {
            ConnectionParamChanged?.Invoke(this, EventArgs.Empty);
        }
    }
}